package me.itsoo.artemis.framework.core.util;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.SecureRandom;

/**
 * Encrypts
 *
 * @author zxy
 * @version 0.0.1
 * @since 2023/5/1
 */
public class Encrypts {

    private final SecureRandom secureRandom;

    private final SecretKey secretKey;

    private Encrypts() {
        this.secureRandom = null;
        this.secretKey = null;
    }

    private Encrypts(String rules) {
        this.secureRandom = new SecureRandom(rules.getBytes(StandardCharsets.UTF_8));
        this.secretKey = new SecretKeySpec(this.getSecretKey().getEncoded(), "AES");
    }

    /**
     * create
     *
     * @return Encrypts
     */
    public static Encrypts create() {
        return new Encrypts();
    }

    /**
     * create
     *
     * @param rules String
     * @return Encrypts
     */
    public static Encrypts create(String rules) {
        Assert.notNull(rules, "'rules' cannot be null.");

        return new Encrypts(rules);
    }

    /**
     * MD5
     *
     * @param content String
     * @return String
     */
    public String md5Encode(String content) {
        try {
            Assert.notNull(content, "'content' cannot be null.");

            final MessageDigest message = MessageDigest.getInstance("MD5");
            final byte[] bytes = content.getBytes(StandardCharsets.UTF_8);
            return String.format("%032x", new BigInteger(1, message.digest(bytes)));
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * AES 加密
     *
     * @param content String
     * @return String
     */
    public String aesEncode(String content) {
        try {
            Assert.notNull(content, "'content' cannot be null.");
            Assert.notNull(this.secureRandom, "'rules' have not been set yet.");

            final byte[] byteEncode = content.getBytes(StandardCharsets.UTF_8);
            final byte[] byteAes = this.getCipher(1).doFinal(byteEncode);
            return (new BASE64Encoder()).encode(byteAes);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * AES 解密
     *
     * @param content String
     * @return String
     */
    public String aesDecode(String content) {
        try {
            Assert.notNull(content, "'content' cannot be null.");
            Assert.notNull(this.secureRandom, "'rules' have not been set yet.");

            final byte[] byteContent = (new BASE64Decoder()).decodeBuffer(content);
            final byte[] byteDecode = this.getCipher(2).doFinal(byteContent);
            return new String(byteDecode, StandardCharsets.UTF_8);
        } catch (Exception e) {
            return null;
        }
    }

    private SecretKey getSecretKey() {
        try {
            final KeyGenerator kg = KeyGenerator.getInstance("AES");
            kg.init(128, this.secureRandom);
            return kg.generateKey();
        } catch (Exception e) {
            return null;
        }
    }

    private Cipher getCipher(int mode) {
        try {
            final Cipher cipher = Cipher.getInstance("AES");
            cipher.init(mode, this.secretKey);
            return cipher;
        } catch (Exception e) {
            return null;
        }
    }
}
